/**
* @project nanorpc
* @file EchoServer.cc
* @author  S Roychowdhury <sroycode AT gmail DOT com>
* @version 1.0
*
* @section LICENSE
*
* Copyright (c) 2013 S Roychowdhury
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* @section DESCRIPTION
*
* example: echo server
*
*/
#include <iostream>
using namespace std;
#include <unistd.h>
#include <signal.h>
#include <stdio.h>
#include <iostream>
#include "RpcServer.hh"
#include "echo.pb.h"
#include "EchoEndpoint.hh"

#include "yolo.h"
#include <opencv2/opencv.hpp>
using namespace cv;

class EchoServiceImpl : public echo::EchoService
{
  public:
    Yolo yolo;
    EchoServiceImpl()
    {
	yolo.setConfigFilePath("cfg/yolo.cfg");
	yolo.setDataFilePath("cfg/coco.data");
	yolo.setWeightFilePath("yolo.weights");
	yolo.setAlphabetPath("data/labels/");
	yolo.setNameListFile("data/coco.names");
    };

    virtual void Echo1(::google::protobuf::RpcController *controller,
		       const ::echo::EchoRequest *request,
		       ::echo::EchoResponse *response,
		       ::google::protobuf::Closure *done)
    {
	std::cerr << "Received1: " << request->message().c_str() << std::endl;
	response->set_response(std::string("You sent1: ") + request->message());
	if (done)
	{
	    done->Run();
	}
    }
    virtual void Echo2(::google::protobuf::RpcController *controller,
		       const ::echo::EchoRequest *request,
		       ::echo::EchoResponse *response,
		       ::google::protobuf::Closure *done)
    {
	std::cerr << "Received2: " << request->message().c_str() << std::endl;
	response->set_response(std::string("You sent2: ") + request->message());
	if (done)
	{
	    done->Run();
	}
    }
    virtual void yolo_detect(::google::protobuf::RpcController *controller,
			     const ::echo::DetectRequest *request,
			     ::echo::DetectResponse *response,
			     ::google::protobuf::Closure *done)
    {

	std::cout << "Received2 yolo_detect	" << request->img_name() << endl;

	Mat img = imread(request->img_name());

	// imshow("xx", img);
	// waitKey(0);
	vector<DetectedObject> detection;
	yolo.detect(img, detection);

	for (int i = 0; i < detection.size(); i++)
	{
	    DetectedObject &o = detection[i];
	    //        cv::rectangle(img, o.bounding_box, cv::Scalar(255, 0, 0), 2);

	    ::echo::DetectData *res = response->add_data();
	    res->set_type(yolo.getNames()[o.object_class]);
	    // res->set_x(1 * i);
	    // res->set_y(2 * i);
	    // res->set_width(3 * i);
	    // res->set_height(4 * i);

	    res->set_x(o.bounding_box.x);
	    res->set_y(o.bounding_box.y);
	    res->set_width(o.bounding_box.width);
	    res->set_height(o.bounding_box.height);
	}
	cout << response->data_size() << endl;

	// std::cerr << "Received2: " << request->message().c_str() << std::endl;
	// response->set_response(std::string("You yolo_detect: ") + request->message());
	if (done)
	{
	    done->Run();
	}
    }
};

void OnExit(int sig)
{
    std::cerr << "Exiting on ^C " << sig << std::endl;
}

int main(int argc, char *argv[])
{
    signal(SIGINT, OnExit);
    try
    {
	nrpc::RpcServer rpc_server(ECHO_ENDPOINT_PORT);
	::google::protobuf::Service *service = new EchoServiceImpl();
	rpc_server.RegisterService(service);
	rpc_server.Start();
    }
    catch (nn::exception &e)
    {
	std::cerr << "NN EXCEPTION : " << e.what() << std::endl;
    }
    catch (std::exception &e)
    {
	std::cerr << "STD EXCEPTION : " << e.what() << std::endl;
    }
    catch (...)
    {
	std::cerr << " UNTRAPPED EXCEPTION " << std::endl;
    }
    return 0;
}
